<script lang="ts" setup>
import { reactive, ref, nextTick } from 'vue'
import * as xlsx from 'xlsx'
import va from '@/rules/index'
import type {
  FormInstance,
  FormRules,
  UploadInstance,
  UploadProps,
  UploadRawFile,
  ElScrollbar,
} from 'element-plus'
import type { IFieldProps } from './interface'

// Define types for better type safety
type RuleType = 'none' | 'age' | 'date' | 'phone' | 'email' | 'rex'
type ErrorAction = 1 | 0
type DataCheck = 1 | 0

interface RuleOption {
  label: string
  value: RuleType
}

interface FormField {
  excelFieldName: string
  databaseFieldName?: string
  rulesType: RuleType
  rulesValue: string
  errorAction?: ErrorAction
  dataCheck?: DataCheck
  databaseFieldRequired?: boolean
}

interface FormData {
  fileList: unknown[]
  fields: FormField[]
  excelData: unknown[]
  errorAction: ErrorAction
  dataCheck: DataCheck
  [key: string]: unknown
}

interface FormDialog {
  top: string
  width: string
  title: string
  span: number
  visible: boolean
}

const emit = defineEmits<{
  (e: 'success'): void
}>()

// Props

interface ComponentProps {
  fields?: IFieldProps[]
  downTmp?: string
}

// Props with defaults
const props = withDefaults(defineProps<ComponentProps>(), {
  fields: () => [],
  downTmp: undefined,
})

const uploadRef = ref<UploadInstance>()
const formRef = ref<FormInstance>()
const innerRef = ref<HTMLDivElement>()
const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>()

const stepActive = ref(0)
const saveLoading = ref(false)

const formData = ref<FormData>({
  fileList: [],
  fields: [],
  excelData: [],
  errorAction: 1,
  dataCheck: 1,
})

const formRules = reactive<FormRules>({
  fileList: [va.required()],
})

const formDialog = reactive<FormDialog>({
  top: '10vh',
  width: '960px',
  title: '导入',
  span: 12,
  visible: false,
})

const excelFields = ref<string[]>([])
const excelDatas = ref<Record<string, unknown>[]>([])

const rulesOptions = ref<RuleOption[]>([
  { label: '无', value: 'none' },
  { label: '数值', value: 'age' },
  { label: '日期', value: 'date' },
  { label: '手机号', value: 'phone' },
  { label: '邮箱号码', value: 'email' },
  { label: '正则表达式', value: 'rex' },
])

// Initialize form fields based on props
props.fields.forEach((element: IFieldProps) => {
  if (element.import === true) {
    formData.value.fields.push({
      excelFieldName: '',
      databaseFieldName: element.prop,
      rulesType: 'none',
      rulesValue: '',
      databaseFieldRequired: true,
    })
  }
})

const show = async (): Promise<void> => {
  formDialog.visible = true
}

const readFile = (file: File): Promise<string | ArrayBuffer | null> => {
  return new Promise((resolve) => {
    const reader = new FileReader()
    reader.readAsBinaryString(file)
    reader.onload = (ev) => {
      resolve(ev.target?.result ?? null)
    }
  })
}

const readExcelFile = async (file: File, sheetIndex: number): Promise<unknown[] | false> => {
  try {
    const data = await readFile(file)
    if (!data) return false

    const workbook = xlsx.read(data, { type: 'binary' })
    const worksheet = workbook.Sheets[workbook.SheetNames[sheetIndex]]
    const jsonData = xlsx.utils.sheet_to_json(worksheet)

    return jsonData
  } catch (error) {
    saveLoading.value = false
    console.error('Error reading Excel file:', error)
    return false
  }
}

const beforeUpload = (file: UploadRawFile | undefined): boolean => {
  if (!file) return false

  try {
    readExcelFile(file, 0)
    return false
  } catch (error) {
    saveLoading.value = false
    console.error('Error in before upload:', error)
    return false
  }
}

const handleExceed: UploadProps['onExceed'] = (files) => {
  uploadRef.value?.clearFiles()
  const file = files[0] as UploadRawFile
  uploadRef.value?.handleStart(file)
}

const handleChange: UploadProps['onChange'] = (uploadFile) => {
  beforeUpload(uploadFile?.raw)
}

const getDatabaseFields = (row: { databaseFieldRequired?: boolean }): IFieldProps[] => {
  if (row.databaseFieldRequired) {
    return props.fields.filter((item) => item.import === true)
  }

  const checkFieldNames = formData.value.fields.map((item) => item.databaseFieldName)
  return props.fields
    .filter((item) => !(item.import === true))
    .map((item) => ({
      ...item,
      disabled: checkFieldNames.includes(item.prop),
    }))
}

const addFieldMapping = (): void => {
  if (!formData.value.fields) {
    formData.value.fields = []
  }

  const availableField = getDatabaseFields({}).find((item) => !item.disabled)
  formData.value.fields.push({
    excelFieldName: '',
    databaseFieldName: availableField?.prop,
    rulesType: 'none',
    rulesValue: '',
    databaseFieldRequired: false,
  })

  nextTick(() => {
    scrollbarRef.value?.setScrollTop(innerRef.value?.clientHeight ?? 0)
  })
}

const removeFieldMapping = (index: number): void => {
  formData.value.fields.splice(index, 1)
}

const nextStep = async (): Promise<void> => {
  const formEl = formRef.value
  if (!formEl) return

  saveLoading.value = true

  try {
    await formEl.validate()

    switch (stepActive.value) {
      case 0:
        // Handle file upload step
        break
      case 1:
        // Handle field mapping step
        break
      default:
        break
    }

    stepActive.value += 1
  } catch (error) {
    console.error('Form validation error:', error)

    if (stepActive.value === 1) {
      ElMessage({
        message: '必填字段的映射关系必填',
        type: 'warning',
        grouping: true,
      })
    }
  } finally {
    saveLoading.value = false
  }
}

const successClose = (): void => {
  formDialog.visible = false
  emit('success')
}

defineExpose({ show })
</script>

<template>
  <el-button type="primary" plain icon="Upload" @click="show()">导入</el-button>

  <el-dialog
    :title="formDialog.title"
    v-model="formDialog.visible"
    :top="formDialog.top"
    :width="formDialog.width"
    :close-on-click-modal="false"
    :append-to-body="true"
    destroy-on-close
  >
    <el-steps :active="stepActive" finish-status="success" simple>
      <el-step title="选择文件" />
      <el-step title="字段映射" />
      <el-step title="导入配置" />
      <el-step title="数据概况" />
      <el-step title="导入结果" />
    </el-steps>
    <div class="mt-4">
      <el-form
        :model="formData"
        :rules="formRules"
        ref="formRef"
        label-width="90px"
        label-suffix=":"
        label-position="top"
      >
        <!-- 第一步上传文件 -->
        <template v-if="stepActive === 0">
          <el-form-item label="上传文件" prop="fileList">
            <el-upload
              ref="uploadRef"
              v-model:file-list="formData.fileList"
              class="w-full"
              accept=".xls, .xlsx"
              drag
              action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
              :multiple="false"
              :limit="1"
              :auto-upload="false"
              :on-change="handleChange"
              :on-exceed="handleExceed"
            >
              <el-icon class="el-icon--upload">
                <upload-filled />
              </el-icon>
              <div class="el-upload__text">将文件拖到此处，或 <em>点击上传</em></div>
              <template #tip>
                <div class="el-upload__tip">
                  <span class="mr-2">仅允许导入xls、xlsx格式文件。</span>
                  <el-link underline="never" type="primary" :href="downTmp" target="_blank"
                    >下载模板</el-link
                  >
                </div>
              </template>
            </el-upload>
          </el-form-item>
        </template>
        <!-- 第二部建立映射关系 -->
        <template v-if="stepActive === 1">
          <el-card shadow="never" :body-style="{ padding: '0px' }">
            <div class="flex p-2">
              <div class="w-8 text-center mr-2">序号</div>
              <div class="flex-1">
                <el-row :gutter="20">
                  <el-col :span="8">
                    <div class="text-center">数据库字段</div>
                  </el-col>
                  <el-col :span="8">
                    <div class="text-center">excel字段</div>
                  </el-col>
                  <el-col :span="8">
                    <div class="text-center">数据校验</div>
                  </el-col>
                </el-row>
              </div>
              <div class="w-8 text-center ml-2">操作</div>
            </div>
          </el-card>
          <el-card shadow="never" :body-style="{ padding: '0px' }" class="mt-2">
            <el-scrollbar
              ref="scrollbarRef"
              :height="formData?.fields?.length > 5 ? '220px' : 'auto'"
              always
            >
              <div class="px-2 py-4" ref="innerRef">
                <div
                  v-for="(i, index) in formData.fields"
                  class="flex"
                  :class="{ 'pb-2': index < formData?.fields?.length - 1 }"
                  :key="index"
                >
                  <div class="w-8 text-center mr-2" style="line-height: 32px">
                    {{ index + 1 }}
                  </div>
                  <div class="flex-1">
                    <el-row :gutter="20">
                      <el-col :span="8">
                        <el-form-item
                          :prop="['fields', index, 'databaseFieldName']"
                          style="margin: 0"
                        >
                          <el-tooltip
                            effect="dark"
                            content="必填字段"
                            placement="top"
                            :disabled="!i.databaseFieldRequired"
                          >
                            <el-select
                              v-model="i['databaseFieldName']"
                              placeholder="选择"
                              class="w-full"
                              :disabled="i.databaseFieldRequired"
                              clearable
                            >
                              <el-option
                                v-for="(item, index) in getDatabaseFields(i)"
                                :key="item.prop + index.toString()"
                                :label="item.label"
                                :value="item.prop"
                                :disabled="item.disabled"
                              >
                                <span class="float-left mr-2">{{ item.label }}</span>
                                <span class="float-right text-gray-400">{{ item.prop }}</span>
                              </el-option>
                            </el-select>
                          </el-tooltip>
                        </el-form-item>
                      </el-col>
                      <el-col :span="8">
                        <el-form-item
                          :prop="['fields', index, 'excelFieldName']"
                          style="margin: 0"
                          :required="i.databaseFieldRequired"
                          inline-message
                          :show-message="false"
                        >
                          <el-select
                            v-model="i['excelFieldName']"
                            placeholder="映射关系"
                            class="w-full"
                          >
                            <el-option
                              v-for="item in excelFields"
                              :key="item"
                              :label="item"
                              :value="item"
                            />
                          </el-select>
                        </el-form-item>
                      </el-col>
                      <el-col :span="8">
                        <el-form-item :prop="['fields', index, 'rulesType']" style="margin: 0">
                          <el-select
                            v-model="i['rulesType']"
                            placeholder="选择"
                            class="w-full"
                            v-if="i['rulesType'] !== 'rex'"
                          >
                            <el-option
                              v-for="item in rulesOptions"
                              :key="item.value"
                              :label="item.label"
                              :value="item.value"
                            >
                              <span class="float-left mr-2">{{ item.label }}</span>
                              <span class="float-right text-gray-400">{{ item.value }}</span>
                            </el-option>
                          </el-select>

                          <el-input v-model="i['rulesValue']" placeholder="输入" v-else>
                            <template #prepend>
                              <el-select
                                v-model="i['rulesType']"
                                placeholder="选择"
                                style="width: 85px"
                              >
                                <el-option
                                  v-for="item in rulesOptions"
                                  :key="item.value"
                                  :label="item.label"
                                  :value="item.value"
                                >
                                  <span class="float-left mr-2">{{ item.label }}</span>
                                  <span class="float-right text-gray-400">{{ item.value }}</span>
                                </el-option>
                              </el-select>
                            </template>
                          </el-input>
                        </el-form-item>
                      </el-col>
                    </el-row>
                  </div>
                  <div class="w-8 text-center ml-2">
                    <el-tooltip
                      v-if="!i.databaseFieldRequired"
                      effect="dark"
                      content="移除"
                      placement="top"
                    >
                      <el-button text icon="Close" circle @click="removeFieldMapping(index)" />
                    </el-tooltip>
                    <el-tooltip v-else effect="dark" content="必填字段不可移除" placement="top">
                      <el-button text icon="InfoFilled" circle />
                    </el-tooltip>
                  </div>
                </div>
                <el-empty
                  description="请点击下方添加按钮增加映射关系"
                  v-if="formData?.fields?.length === 0"
                />
              </div>
            </el-scrollbar>
          </el-card>
        </template>
        <!-- 第三步导入配置 -->
        <template v-if="stepActive === 2">
          <el-card shadow="never" :body-style="{ padding: '20px' }">
            <el-row :gutter="20">
              <el-col :span="24">
                <el-form-item label="执行数据校验" prop="dataCheck" required>
                  <el-radio-group v-model="formData.dataCheck">
                    <el-radio :value="1">是</el-radio>
                    <el-radio :value="0">否</el-radio>
                  </el-radio-group>
                </el-form-item>
              </el-col>
              <el-col :span="24">
                <el-form-item label="遇到错误" prop="errorAction" required>
                  <el-radio-group v-model="formData.errorAction">
                    <el-radio :value="1">继续</el-radio>
                    <el-radio :value="0">停止</el-radio>
                  </el-radio-group>
                </el-form-item>
              </el-col>
            </el-row>
          </el-card>
        </template>
        <!-- 第四步信息 -->
        <template v-if="stepActive === 3">
          <el-card shadow="never" :body-style="{ padding: '20px' }">
            <el-descriptions title="数据概况">
              <el-descriptions-item label="总数据量">{{ excelDatas.length }} </el-descriptions-item>
              <el-descriptions-item label="检验通过量"
                >{{ excelDatas.length }}
              </el-descriptions-item>
              <el-descriptions-item label="检验失败量"
                >{{ excelDatas.length }}
              </el-descriptions-item>
            </el-descriptions>
          </el-card>
        </template>
        <!-- 第五步结果 -->
        <template v-if="stepActive === 4">
          <el-card shadow="never" :body-style="{ padding: '20px' }">
            <el-result icon="success" title="导入成功" sub-title="Please follow the instructions">
              <template #extra>
                <el-button type="primary" @click="successClose()">关闭</el-button>
              </template>
            </el-result>
          </el-card>
        </template>
      </el-form>
    </div>
    <template #footer>
      <span class="dialog-footer-left float-left" v-if="stepActive === 1">
        <el-tooltip
          effect="dark"
          content="超出"
          placement="top"
          :disabled="formData?.fields?.length < props.fields.length"
        >
          <el-button
            icon="CirclePlus"
            @click="addFieldMapping"
            :disabled="formData?.fields?.length >= props.fields.length"
            >添加</el-button
          >
        </el-tooltip>
      </span>
      <span class="dialog-footer">
        <el-button v-if="stepActive > 0 && stepActive < 4" type="primary" @click="stepActive = 0"
          ><el-icon class="el-icon--left"> <DArrowLeft /> </el-icon>上一步</el-button
        >
        <el-button v-if="stepActive < 3" type="primary" @click="nextStep()" :loading="saveLoading"
          >下一步<el-icon class="el-icon--right"> <DArrowRight /> </el-icon
        ></el-button>
        <el-button
          v-if="stepActive === 3"
          type="primary"
          @click="nextStep()"
          icon="CircleCheck"
          :loading="saveLoading"
          auto-insert-space
          >导入</el-button
        >
      </span>
    </template>
  </el-dialog>
</template>
